package org.zjvis.datascience.common.util;

import com.alibaba.druid.util.Base64;
import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.text.DecimalFormat;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @description 文件六转换工具类
 * @date 2021-08-27
 */
public class FileUtil {

    private final static Logger logger = LoggerFactory.getLogger(FileUtil.class);

    public static String inputStream2String(InputStream is) throws IOException {
        return inputStream2String(is, false);
    }

    /**
     * inputStream转字符串
     *
     * @param is
     * @return
     * @throws IOException
     */
    public static String inputStream2String(InputStream is, boolean br) throws IOException {
        if (is == null) {
            return "";
        }
        String eol = br ? "\r\n" : "";
        BufferedReader in = new BufferedReader(new InputStreamReader(is));
        StringBuffer buffer = new StringBuffer();
        String line = "";
        while ((line = in.readLine()) != null) {
            buffer.append(line).append(eol);
        }
        return buffer.toString();
    }

    /**
     * inputStream转base64
     *
     * @param in
     * @return
     * @throws Exception
     */
    public static String inputStream2Base64(InputStream in) throws Exception {
        // 将图片文件转化为字节数组字符串，并对其进行Base64编码处理
        byte[] data = null;

        // 读取图片字节数组
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] buff = new byte[100];
            int rc = 0;
            while ((rc = in.read(buff, 0, 100)) > 0) {
                out.write(buff, 0, rc);
            }
            data = out.toByteArray();
        } catch (IOException e) {
            logger.error(e.getMessage());
            throw new Exception("base64转换异常");
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    logger.error(e.getMessage());
                }
            }
        }

        return Base64.byteArrayToBase64(data);
    }

    public static String longSize2Str(long size) {
        StringBuffer bytes = new StringBuffer();
        DecimalFormat format = new DecimalFormat("###.0");
        if (size >= 1024 * 1024 * 1024) {
            double i = (size / (1024.0 * 1024.0 * 1024.0));
            bytes.append(format.format(i)).append("GB");
        } else if (size >= 1024 * 1024) {
            double i = (size / (1024.0 * 1024.0));
            bytes.append(format.format(i)).append("MB");
        } else if (size >= 1024) {
            double i = (size / (1024.0));
            bytes.append(format.format(i)).append("KB");
        } else {
            if (size <= 0) {
                bytes.append("0B");
            } else {
                bytes.append((int) size).append("B");
            }
        }
        return bytes.toString();
    }

    public static Long strSize2Long(String sizeStr) {
        String lowerCaseSizeStr = sizeStr.toUpperCase();
        Matcher matcher = Pattern.compile("[A-Z_]+").matcher(lowerCaseSizeStr);
        if (matcher.find()) {
            int index = matcher.start();
            String unit = lowerCaseSizeStr.substring(index);
            double times = 0;
            switch (unit) {
                case "B":
                    times = 1;
                    break;
                case "KB":
                    times = 1024;
                    break;
                case "MB":
                    times = 1024 * 1024;
                    break;
                case "GB":
                    times = 1024 * 1024 * 1024;
                    break;
            }
            return new Double(Double.parseDouble(lowerCaseSizeStr.substring(0, index)) * times)
                    .longValue();
        } else {
            return 0L;
        }

    }

    /**
     * 分快读取
     *
     * @param path 文件路径
     * @param blockSize 块大小
     * @param pos 指针位置
     * @return byte[]
     */
    public static byte[] randomRead(String path, int blockSize, int pos) {
        RandomAccessFile raRead = null;
        try {
            raRead = new RandomAccessFile(path, "r");
            //获取RandomAccessFile对象文件指针的位置，初始位置是0
            // 移动文件指针位置,和每次读取文件的大小有关
            raRead.seek(pos*blockSize);
            //每次读取文件的大小
            byte[] bytes = new byte[blockSize];
            int readSize = raRead.read(bytes);
            if (readSize <= 0) {
                return null;
            }
            //不足blockSize需要拷贝去掉空字节
            if (readSize < blockSize) {
                byte[] copy = new byte[readSize];
                System.arraycopy(bytes, 0, copy, 0, readSize);
                return copy;
            }

            return bytes;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (raRead != null) {
                try {
                    raRead.close();
                } catch (IOException e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
        return null;
    }

    public static void concat(File targetFile, List<File> fileChunks){
        try (BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
                new FileOutputStream(targetFile, true))) {
            fileChunks.forEach(chunk -> {
                try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(chunk))) {
                    IOUtils.copy(bufferedInputStream, bufferedOutputStream);
                } catch (IOException e) {
                    throw new UncheckedIOException(e);
                }
            });
        }catch (Exception e){
            logger.error("concat file failed, since " +e.getMessage(), e);
        }
    }


    public static void main(String[] args) {
        List<File> chunkFiles = Lists.newArrayList();
        String fileNameExt = "CSV-16596812900721646a1no6";
        for (int i = 0; i < 1; i ++){
            chunkFiles.add(new File("D:\\Projects\\aiworks\\csv_tmp/\\" + fileNameExt + "_" + i +".csv"));
        }
        FileUtil.concat(new File("D:\\Projects\\aiworks\\csv_tmp/\\" + fileNameExt +"1.csv"), chunkFiles);
    }

}
